-
Notifications
You must be signed in to change notification settings - Fork 89
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
662/mk/use open payments types #1024
Conversation
Currently running into this challenge: when calling
class SubresourceQueryBuilder {
...
execute() {
this.withGraphFetched('paymentPointer')
return super.execute()
}
} Am I overthinking this, and should just go with the standard way we have it now via |
Reading option 1 made think of doing something like option 3. Adrian's idea 👇 might eventually help with this. |
I was trying it out with the example above of overriding Instead of solving it programmatically, what if we just stored a Otherwise, I'm leaning toward making |
I vote async |
@@ -84,7 +84,6 @@ export class IncomingPayment | |||
} | |||
} | |||
|
|||
public paymentPointer!: PaymentPointer |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no non-null assertion since we can start removing withGraphFetched('paymentPointer')
from the DB calls
@@ -131,8 +130,15 @@ export class IncomingPayment | |||
this.receivedAmountValue = amount.value | |||
} | |||
|
|||
public get url(): string { | |||
return `${this.paymentPointer.url}${IncomingPayment.urlPath}/${this.id}` | |||
public async getUrl(fetchedPaymentPointer?: PaymentPointer): Promise<string> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding fetchedPaymentPointer
in-case you already have the paymentPointer and don't want to grab it again, like in toOpenPaymentsType
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if callers just assigned incomingPayment.paymentPointer = fetchedPaymentPointer
, so that getUrl
+getPaymentPointer
only dealt with whether this.paymentPointer
is defined or not?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Taking a step back, if/when we change subresource urls to not include the payment pointer, we'll no longer need an async getUrl
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm hesitant to do that, since
a) we either have to change the type definitions of getUrl/toOpenPaymentsType
to possibly return undefined
, or throw inside the method if paymentPointer
isn't defined
b) it's not entirely clear that the caller has to do that in order to make these methods work.
Maybe we can
- have
toOpenPaymentsType
take in apaymentPointer
(this would also make it sync), it would require passing inctx.paymentPointer
in most places but I think that's ok - A bit more complicated, but we make a separate
<subresource>WithPaymentPointer
class that constructs a new model with thepaymentPointer
defined, although I'm not sure the additional boilerplate is worth it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To clarify, I'm only suggesting changing getUrl
to
public async getUrl(fetchedPaymentPointer?: PaymentPointer): Promise<string> { | |
public async getUrl(): Promise<string> { |
and callers can optionally define incomingPayment.paymentPointer
to avoid $relatedQuery
in getPaymentPointer
.
return { | ||
id: await this.getUrl(paymentPointer), | ||
paymentPointer: paymentPointer.url, | ||
quoteId: (await this.quote?.getUrl()) ?? undefined, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is optional in the Open Payments API -> should we keep it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤔 I wonder if we should make it required in the spec
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you can only create an Outgoing Payment with a required quoteId
, it would make sense that this would be required here
@@ -66,10 +68,7 @@ export const listSubresource = async <M extends PaymentPointerSubresource>({ | |||
) | |||
const result = { | |||
pagination: pageInfo, | |||
result: page.map((item: M) => { | |||
item.paymentPointer = ctx.paymentPointer |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are fetching paymentPointer on the fly (whenever it's missing), this line isn't necessary
id: string | ||
paymentPointer: string | ||
incomingAmount?: AmountJSON | ||
receivedAmount: AmountJSON |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@wilsonianb Keeping AmountJSON
over OpenPaymentsAmount
makes sense right? The Amount interface is a more generic thing we use across the code, not necessarily being an "open payments" concept
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 I'm good with keeping amount values as strings in open-payments
and leaving it to callers to (de)serialize.
Going to update the |
): | ||
| OpenPaymentsIncomingPayment | ||
| OpenPaymentsIncomingPaymentWithConnection | ||
| OpenPaymentsIncomingPaymentWithConnectionUrl { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was going to suggest adding an abstract toOpenPaymentsType
to PaymentPointerSubresource
but this one for incoming payments would complicate it
export abstract class PaymentPointerSubresource extends BaseModel { |
toBody: async (payment) => | ||
await incomingPaymentToBody( | ||
payment, | ||
deps.connectionService.getUrl(payment) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we either make this getUrl
async for consistency or rename it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it should be ok as it is, since it's a service method, not a model?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm also ok keeping it as is.
It just stood out against the new async getUrl
s
return { | ||
id: await this.getUrl(paymentPointer), | ||
paymentPointer: paymentPointer.url, | ||
quoteId: (await this.quote?.getUrl()) ?? undefined, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤔 I wonder if we should make it required in the spec
@@ -80,7 +80,7 @@ async function createQuote( | |||
} | |||
|
|||
ctx.status = 201 | |||
ctx.body = quoteToBody(quoteOrErr) | |||
ctx.body = await quoteToBody(quoteOrErr) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ctx.body = await quoteToBody(quoteOrErr) | |
ctx.body = await quoteOrErr.toOpenPaymentsType() |
Remove quoteToBody
@@ -131,8 +130,15 @@ export class IncomingPayment | |||
this.receivedAmountValue = amount.value | |||
} | |||
|
|||
public get url(): string { | |||
return `${this.paymentPointer.url}${IncomingPayment.urlPath}/${this.id}` | |||
public async getUrl(fetchedPaymentPointer?: PaymentPointer): Promise<string> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if callers just assigned incomingPayment.paymentPointer = fetchedPaymentPointer
, so that getUrl
+getPaymentPointer
only dealt with whether this.paymentPointer
is defined or not?
* chore(backend): make toOpenPaymentType sync * chore(backend): make quote.toOpenPaymentsType sync * chore(backend): convert tests to sync * chore(backend): update tests
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops, here's some several day old comments that I didn't realize were pending in a review
id: string | ||
paymentPointer: string | ||
incomingAmount?: AmountJSON | ||
receivedAmount: AmountJSON |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 I'm good with keeping amount values as strings in open-payments
and leaving it to callers to (de)serialize.
@@ -131,8 +130,15 @@ export class IncomingPayment | |||
this.receivedAmountValue = amount.value | |||
} | |||
|
|||
public get url(): string { | |||
return `${this.paymentPointer.url}${IncomingPayment.urlPath}/${this.id}` | |||
public async getUrl(fetchedPaymentPointer?: PaymentPointer): Promise<string> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Taking a step back, if/when we change subresource urls to not include the payment pointer, we'll no longer need an async getUrl
.
toBody: async (payment) => | ||
await incomingPaymentToBody( | ||
payment, | ||
deps.connectionService.getUrl(payment) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm also ok keeping it as is.
It just stood out against the new async getUrl
s
@@ -131,8 +130,15 @@ export class IncomingPayment | |||
this.receivedAmountValue = amount.value | |||
} | |||
|
|||
public get url(): string { | |||
return `${this.paymentPointer.url}${IncomingPayment.urlPath}/${this.id}` | |||
public async getUrl(fetchedPaymentPointer?: PaymentPointer): Promise<string> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To clarify, I'm only suggesting changing getUrl
to
public async getUrl(fetchedPaymentPointer?: PaymentPointer): Promise<string> { | |
public async getUrl(): Promise<string> { |
and callers can optionally define incomingPayment.paymentPointer
to avoid $relatedQuery
in getPaymentPointer
.
| OpenPaymentsIncomingPaymentWithConnection | ||
| OpenPaymentsIncomingPaymentWithConnectionUrl | ||
|
||
public toOpenPaymentsType( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if we added some model.test.ts
s at least to test toOpenPaymentsType
?
Or are existing response body checks in routes tests good enough?
assetScale: incomingPayment.receivedAmount.assetScale | ||
} | ||
}), | ||
getBody: (incomingPayment, list) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could this instead be
getBody: (incomingPayment, list) => { | |
getBody: (incomingPayment, list) => incomingPayment.toOpenPaymentsType(paymentPointer) |
with some possible special assignment for ilpStreamConnection
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In terms of the connection, we would be able to do something like:
getBody: (incomingPayment, list) => ({
...incomingPayment.toOpenPaymentsType(paymentPointer),
ilpStreamConnection: list
? `${config.openPaymentsUrl}/connections/${incomingPayment.connectionId}`
: {
id: `${config.openPaymentsUrl}/connections/${incomingPayment.connectionId}`,
ilpAddress: expect.stringMatching(
/^test\.rafiki\.[a-zA-Z0-9_-]{95}$/
),
sharedSecret: expect.stringMatching(/^[a-zA-Z0-9-_]{43}$/),
assetCode: incomingPayment.receivedAmount.assetCode,
assetScale: incomingPayment.receivedAmount.assetScale
}
}),
Since incomingPayment.toOpenPaymentsType
expect a Connection
, we wouldn't be able to use expect.stringMatching(...)
, but would have to create a Connection
instance with proper credentials
etc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i.e. I'm not sure if that's a much better solution
}) | ||
|
||
describe('toOpenPaymentsType', () => { | ||
test('returns incoming payment without connection provided', async () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if there was a single test.each
to make clear that output is the same other than ilpStreamConnection
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking this, but having a test case where the connection
var in the test.each
case was either
const connection = `${config.openPaymentsUrl}/connections/${incomingPayment.connectionId}`
or
const connection = Connection.fromPayment({
payment: incomingPayment,
openPaymentsUrl: config.openPaymentsUrl,
credentials: {
ilpAddress: 'test.ilp' as IlpAddress,
sharedSecret: Buffer.from('')
}
})
didn't feel nice
Changes proposed in this pull request
open-payments
packagetoOpenPaymentsType()
method for subresources to convert from model to the correspondingopen-payments
type, removingtoJSON
types and method where necessarytoOpenPaymentsType()
methods in the route handlers when creating responseContext
Checklist
fixes #number